/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package vkplayer;

import com.epam.player.vkapi.authentication.Authentication;
import com.epam.player.vkapi.exceptions.CredentialsWrongException;
import com.epam.player.vkapi.exceptions.TemporarilyUnavailableServiceException;
import com.epam.player.vkapi.model.Song;
import com.epam.player.vkapi.music.MusicManager;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.*;
import javafx.geometry.Orientation;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
import vkplayer.common.Constant;
import vkplayer.exceptions.PropertiesLoadException;
import vkplayer.logic.PropertiesLoader;

/**
 *
 * @author Admin
 */
public class VKPlayer extends Application {

    private static ImageView background = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/VKPlayer-BG.png")));
    private static ImageView imafeClose = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/close.png")));
    private static ImageView imageListShow = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/MP3_handoff_playlist_rollover.png")));
    private static ImageView imagePlay = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/MP3_handoff_play_rollover.png")));
    private static ImageView imagePause = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/pause.png")));
    private static ImageView imageVolume = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/MP3_handoff_volume_icon.png")));
    private static ImageView imageForfard = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/MP3_handoff_playFoward.png")));
    private static ImageView imageBack = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/MP3_handoff_playBack.png")));
    private static ImageView imageStop = new ImageView(new Image(VKPlayer.class.getResourceAsStream("images/MP3_handoff_stop.png")));
    private MediaPlayer mediaPlayer;
    Duration duration;
    Slider timeSlider = new Slider();
    Label playTime = new Label();
    Slider volumeSlider = new Slider();
    private boolean atEndOfMedia = false;
    private boolean stopRequested = false;
    List<Song> songs = null;
    Button buttonPlay = new Button();
    double numX;
    double numY;

    public static void main(String[] args) {
        launch(args);
    }
    Group root = new Group();
    Scene scene;

    @Override
    public void start(final Stage primaryStage) {
        scene = new Scene(root, 500, 560);

        root.setAutoSizeChildren(false);
        Pane pane = new Pane();

//        scene.setOnMouseMoved(new EventHandler<MouseEvent>() {
//
//            @Override
//            public void handle(MouseEvent arg0) {
//                if ((arg0.getSceneX() > scene.getX() + 50)
//                        && (arg0.getSceneX() < scene.getX() + 100)
//                        && (arg0.getSceneY() > scene.getY() + 20)
//                        && (arg0.getSceneY() < scene.getY() + 40)) {
//                    scene.setCursor(Cursor.MOVE);
//                } else {
//                    scene.setCursor(Cursor.DEFAULT);
//                }
//            }
//        });
//
//        scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
//
//            @Override
//            public void handle(MouseEvent arg0) {
//                if (scene.getCursor() == Cursor.MOVE) {
//                    primaryStage.setX(arg0.getScreenX() - 100);
//                    primaryStage.setY(arg0.getScreenY() - 80);
//                }
//            }
//        });
        // button Volume
        volumeSlider.setVisible(false);
        Button buttonVolume = new Button();
        buttonVolume.setGraphic(imageVolume);
        buttonVolume.resizeRelocate(445, 123, 20, 20);
        buttonVolume.setId("navigateButton");
        buttonVolume.setCursor(Cursor.HAND);
        buttonVolume.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                if (!volumeSlider.isVisible()) {
                    volumeSlider.setVisible(true);
                } else {
                    volumeSlider.setVisible(false);
                }
            }
        });
//   button Close

        Button buttonClose = new Button();
        buttonClose.setGraphic(imafeClose);
        buttonClose.resizeRelocate(37, 20, 20, 20);
        buttonClose.setId("buttonClose");
        buttonClose.setCursor(Cursor.HAND);
        buttonClose.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                Platform.exit();
            }
        });

        PropertiesLoader propertiesLoader = new PropertiesLoader();
        Map<String, String> prop = null;
        try {
            prop = propertiesLoader.getProperties();
        } catch (PropertiesLoadException ex) {
            prop = new HashMap<String, String>();
            prop.put(Constant.EMAIL, "enter your email");
            prop.put(Constant.PASS, "enter your pass");
            propertiesLoader.saveProperties(prop);
            Logger.getLogger(VKPlayer.class.getName()).log(Level.SEVERE, "Open VKPlayerConfig.properties in " + Constant.pathConfigFile, ex);
        }
        Authentication authentication = new Authentication();
        try {
            authentication.loginToVK(prop.get(Constant.EMAIL), prop.get(Constant.PASS));
        } catch (CredentialsWrongException ex) {
            Logger.getLogger(VKPlayer.class.getName()).log(Level.SEVERE, "Open VKPlayerConfig.properties in " + Constant.pathConfigFile, ex);
        } catch (TemporarilyUnavailableServiceException ex) {
            Logger.getLogger(VKPlayer.class.getName()).log(Level.SEVERE, null, ex);
        }
        MusicManager musicManager = new MusicManager();

        try {
            songs = musicManager.getPopularSongs(0);
        } catch (TemporarilyUnavailableServiceException ex) {
            Logger.getLogger(VKPlayer.class.getName()).log(Level.SEVERE, null, ex);
        }

        ObservableList<String> data = FXCollections.observableArrayList();
        for (Song song : songs) {
            data.add(song.getAuthor() + " - " + song.getTitle());
        }
        final Text labelSongInfo = new Text(60, 75, "");
        labelSongInfo.setFill(Color.WHITE);


//PlayList
        final ListView<String> list = new ListView<String>();
        list.setMaxHeight(400);
        list.setMinWidth(380);
        list.setLayoutX(113);
        list.setLayoutY(156);
        list.setVisible(false);
        list.setOrientation(Orientation.VERTICAL);
        list.setItems(data);



        list.getSelectionModel().selectedItemProperty().addListener(
                new ChangeListener<String>() {

                    @Override
                    public void changed(ObservableValue<? extends String> ov,
                            String old_val, String new_val) {
                        ReadOnlyIntegerProperty index = list.getSelectionModel().selectedIndexProperty();
                        mediaPlayer.stop();
                        URL url = songs.get(index.intValue()).getUrl();
                        mediaPlayer = new MediaPlayer(new Media(url.toString()));
                        Song song = songs.get(index.intValue());
                        String result = song.getAuthor() + " - " + song.getTitle();
                        if (result.length() > 50) {
                            result = result.substring(0, 50) + "...";
                        }
                        labelSongInfo.setText(result);

                        mediaPlayer.setAutoPlay(true);
                        mediaPlayer.setVolume(volumeSlider.getValue() / 100.0);
                        mediaPlayer.currentTimeProperty().addListener(new ChangeListener<Duration>() {

                            @Override
                            public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
                                updateValues();
                            }
                        });

                        mediaPlayer.setOnPlaying(new Runnable() {

                            @Override
                            public void run() {
                                System.out.println("\t> setOnPlaying:");
                                if (stopRequested) {
                                    mediaPlayer.pause();
                                    stopRequested = false;
                                } else {
                                    buttonPlay.setGraphic(imagePause);
                                }
                            }
                        });

                        mediaPlayer.setOnPaused(new Runnable() {

                            @Override
                            public void run() {
                                System.out.println("\t|| setOnPaused:");
                                buttonPlay.setGraphic(imagePlay);
                            }
                        });

                        mediaPlayer.setOnReady(new Runnable() {

                            @Override
                            public void run() {
                                System.out.println("\t~ setOnReady:");
                                duration = mediaPlayer.getMedia().getDuration();
                                updateValues();
                            }
                        });
                        mediaPlayer.setOnEndOfMedia(new Runnable() {

                            @Override
                            public void run() {
                                System.out.println("\t setOnEndOfMedia:");
                                ReadOnlyIntegerProperty index = list.getSelectionModel().selectedIndexProperty();
                                System.out.println("\t index:" + index.getValue());
                                list.getSelectionModel().select(index.getValue() + 1);
                            }
                        });
                    }
                });




        mediaPlayer = new MediaPlayer(new Media(songs.get(0).getUrl().toString()));
        mediaPlayer.setAutoPlay(false);
        labelSongInfo.setText(songs.get(0).getAuthor() + " - " + songs.get(0).getTitle());
//        String MEDIA_URL = "http://cs5020.userapi.com/u14820114/audio/7075835ed69e.mp3";
//        mediaPlayer = new MediaPlayer(new Media(MEDIA_URL));

        //   button showPlayList
        Button buttonShowList = new Button();
        buttonShowList.setGraphic(imageListShow);
        buttonShowList.setId("navigateButton");
        buttonShowList.setLayoutX(21);
        buttonShowList.setLayoutY(125);
        buttonShowList.setCursor(Cursor.HAND);
        buttonShowList.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                if (!list.isVisible()) {
                    list.setVisible(true);
                } else {
                    list.setVisible(false);
                }
            }
        });

        Button buttonStop = new Button();
        buttonStop.setGraphic(imageStop);
        buttonStop.setId("navigateButton");
        buttonStop.setLayoutX(23);
        buttonStop.setLayoutY(58);
        buttonStop.setCursor(Cursor.HAND);
        buttonStop.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                mediaPlayer.stop();
                buttonPlay.setGraphic(imagePlay);
            }
        });

        Button buttonForfard = new Button();
        buttonForfard.setGraphic(imageForfard);
        buttonForfard.setId("navigateButton");
        buttonForfard.setLayoutX(70);
        buttonForfard.setLayoutY(75);
        buttonForfard.setCursor(Cursor.HAND);
        buttonForfard.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.print("click next");
                ReadOnlyIntegerProperty index = list.getSelectionModel().selectedIndexProperty();
                int result = 0;
                if (index.getValue() < 0) {
                    result = index.getValue() + 2;
                } else {
                    result = index.getValue() + 1;
                }
                System.out.println("\t index:" + index.getValue());
                list.getSelectionModel().select(result);

            }
        });

        Button buttonBack = new Button();
        buttonBack.setGraphic(imageBack);
        buttonBack.setId("navigateButton");
        buttonBack.setLayoutX(6);
        buttonBack.setLayoutY(75);
        buttonBack.setCursor(Cursor.HAND);
        buttonBack.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.print("click prev");
                ReadOnlyIntegerProperty index = list.getSelectionModel().selectedIndexProperty();
                int result = 0;
                if (index.getValue() <= 0) {
                    result = 0;
                } else {
                    result = index.getValue() - 1;
                }
                System.out.println("\t index:" + index.getValue());
                list.getSelectionModel().select(result);

            }
        });


//   button Play

        buttonPlay.setGraphic(imagePlay);
        buttonPlay.setId("navigateButton");
        buttonPlay.setLayoutX(29);
        buttonPlay.setLayoutY(83);
        buttonPlay.setCursor(Cursor.HAND);




        MediaView mediaView = new MediaView(mediaPlayer);
        Pane paneTimeInfo = new Pane();
        paneTimeInfo.maxWidth(100);
        paneTimeInfo.maxHeight(20);
        paneTimeInfo.setLayoutX(130);
        paneTimeInfo.setScaleZ(0);

        // Time label
        Label timeLabel = new Label("Time: ");
        timeLabel.setTextFill(Color.web("#ffffff"));
        timeLabel.setLayoutX(35);
        timeLabel.setLayoutY(85);
        playTime.setTextFill(Color.web("#ffffff"));
        playTime.setLayoutX(80);
        playTime.setLayoutY(85);



        paneTimeInfo.getChildren().addAll(playTime, timeLabel, labelSongInfo);

        volumeSlider.setRotate(-90);
        volumeSlider.setMaxWidth(100);
        volumeSlider.resizeRelocate(410, 80, 0, 0);

        buttonPlay.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                updateValues();
                MediaPlayer.Status status = mediaPlayer.getStatus();
                if (status == MediaPlayer.Status.UNKNOWN
                        || status == MediaPlayer.Status.HALTED) {
                    // don't do anything in these states
                    return;
                }

                if (status == MediaPlayer.Status.PAUSED
                        || status == MediaPlayer.Status.READY
                        || status == MediaPlayer.Status.STOPPED) {
                    // rewind the movie if we're sitting at the end
                    if (atEndOfMedia) {
                        mediaPlayer.seek(mediaPlayer.getStartTime());
                        atEndOfMedia = false;
                        buttonPlay.setGraphic(imagePlay);
                        updateValues();
                    }

                    mediaPlayer.play();
                    buttonPlay.setGraphic(imagePause);
                } else {
                    mediaPlayer.pause();
                }
            }
        });

        mediaPlayer.currentTimeProperty().addListener(new ChangeListener<Duration>() {

            @Override
            public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
                updateValues();
            }
        });

        mediaPlayer.setOnPlaying(new Runnable() {

            @Override
            public void run() {
                System.out.println("\t setOnPlaying: \nstopRequested= " + stopRequested);
                if (stopRequested) {
                    mediaPlayer.pause();
                    stopRequested = false;
                } else {
                    buttonPlay.setGraphic(imagePause);
                }
            }
        });

        mediaPlayer.setOnPaused(new Runnable() {

            @Override
            public void run() {
                System.out.println("\t setOnPaused:");
                buttonPlay.setGraphic(imagePlay);
            }
        });

        mediaPlayer.setOnReady(new Runnable() {

            @Override
            public void run() {
                System.out.println("\t setOnReady:");
                duration = mediaPlayer.getMedia().getDuration();
                updateValues();
            }
        });



        // Time slider
        timeSlider = new Slider();
        timeSlider.setLayoutX(130);
        timeSlider.setLayoutY(120);
        timeSlider.setMinWidth(310);
        timeSlider.valueProperty().addListener(new InvalidationListener() {

            @Override
            public void invalidated(Observable ov) {
                if (timeSlider.isValueChanging()) {
                    // multiply duration by percentage calculated by slider position
                    if (duration != null) {
                        mediaPlayer.seek(duration.multiply(timeSlider.getValue() / 100.0));
                    }
                    updateValues();

                }
            }
        });

        volumeSlider.valueProperty().addListener(new ChangeListener<Number>() {

            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                if (volumeSlider.isValueChanging()) {
                    mediaPlayer.setVolume(volumeSlider.getValue() / 100.0);
                }
            }
        });
        volumeSlider.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent arg0) {
                volumeSlider.setVisible(false);
            }
        });

        pane.getChildren().addAll(buttonClose, buttonBack, buttonForfard, buttonShowList, buttonStop, buttonPlay, list, mediaView, volumeSlider, paneTimeInfo, timeSlider, buttonVolume);
        root.getChildren().addAll(background, pane);
        //  scene.setFill(Color.TRANSPARENT);
        scene.getStylesheets().add(VKPlayer.class.getResource("css/VKPlayer.css").toExternalForm());
        primaryStage.setScene(scene);
        //  primaryStage.initStyle(StageStyle.TRANSPARENT);

        primaryStage.centerOnScreen();

        primaryStage.show();
    }

    private void updateValues() {
        if (playTime != null && timeSlider != null && volumeSlider != null && duration != null) {
            Platform.runLater(new Runnable() {

                @Override
                public void run() {
                    Duration currentTime = mediaPlayer.getCurrentTime();
                    playTime.setText(formatTime(currentTime, duration));
                    timeSlider.setDisable(duration.isUnknown());
                    if (!timeSlider.isDisabled() && duration.greaterThan(Duration.ZERO) && !timeSlider.isValueChanging()) {
                        timeSlider.setValue(currentTime.divide(duration).toMillis() * 100.0);
                    }
                    if (!volumeSlider.isValueChanging()) {
                        volumeSlider.setValue((int) Math.round(mediaPlayer.getVolume() * 100));
                    }
                }
            });
        }
    }

    private String formatTime(Duration elapsed, Duration duration) {
        int intElapsed = (int) Math.floor(elapsed.toSeconds());
        int elapsedHours = intElapsed / (60 * 60);
        if (elapsedHours > 0) {
            intElapsed -= elapsedHours * 60 * 60;
        }
        int elapsedMinutes = intElapsed / 60;
        int elapsedSeconds = intElapsed - elapsedHours * 60 * 60 - elapsedMinutes * 60;

        if (duration.greaterThan(Duration.ZERO)) {
            int intDuration = (int) Math.floor(duration.toSeconds());
            int durationHours = intDuration / (60 * 60);
            if (durationHours > 0) {
                intDuration -= durationHours * 60 * 60;
            }
            int durationMinutes = intDuration / 60;
            int durationSeconds = intDuration - durationHours * 60 * 60 - durationMinutes * 60;

            if (durationHours > 0) {
                return String.format("%d:%02d:%02d/%d:%02d:%02d",
                        elapsedHours, elapsedMinutes, elapsedSeconds,
                        durationHours, durationMinutes, durationSeconds);
            } else {
                return String.format("%02d:%02d/%02d:%02d",
                        elapsedMinutes, elapsedSeconds,
                        durationMinutes, durationSeconds);
            }
        } else {
            if (elapsedHours > 0) {
                return String.format("%d:%02d:%02d",
                        elapsedHours, elapsedMinutes, elapsedSeconds);
            } else {
                return String.format("%02d:%02d",
                        elapsedMinutes, elapsedSeconds);
            }
        }
    }
}
